<!DOCTYPE html>
<html lang="zh-cn">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="styles.css">
    <title>客户端</title>
</head>

<body>
    <div class="beibeibeibei-panel-warpper">
        <div class="corner-box-warpper">
            <div class="corner-box topright"></div>
            <div class="corner-box bottomright"></div>
            <div class="corner-box bottomleft"></div>
            <div class="corner-box topleft"></div>
        </div>
        <div class="beibeibeibei-panel-border">
            <div id="beibeibeibei-panel">
                <div class="titlebar">
                    <div class="led" title="连接状态">
                        <svg width="20" height="20">
                            <ellipse cx="10" cy="10" rx="5" ry="5"></ellipse>
                        </svg>
                    </div>
                    <!-- svg制作方式：Inkscape→全选形状→1+1+17x17,文件→文档属性→19x19 -->
                    <button class="home" title="作者主页" type="button">
                        <a href="https://gitee.com/beibeibeibei" target="_blank" rel="noopener noreferrer">
                            <svg width="19" height="19" viewbox="0 0 19 19">
                                <path
                                    d="M 12.238437,2 C 15.140188,2 17,4.5155458 17,7.9010931 17,10.528328 14.801,13.421712 10.468437,16.672867 a 1.701,1.8389227 0 0 1 -1.9368745,0 C 4.1990001,13.421712 2,10.528328 2,7.9010931 2,4.5155458 3.8598126,2 6.7615625,2 7.8095,2 8.5203125,2.3958792 9.5,3.2940567 10.479875,2.3960819 11.1905,2 12.238437,2 Z"
                                    fill="black" />
                            </svg>
                        </a>
                    </button>
                    <button class="rule" title="设置规则" type="button">
                        <svg width="19" height="19">
                            <path d="M11,0 L0,11 L7,18 L18,7 L18,0 Z M12,6 m-3,0 a3,3 0 1,0 6,0 a3,3 0 1,0-6,0"
                                fill-rule="evenodd" fill="black" />
                        </svg>
                    </button>
                    <button class="test" title="发送测试消息" type="button">
                        <svg width="19" height="19">
                            <polygon points="1,3 9,8 17,3" fill="black"></polygon>
                            <polygon points="1,5 1,15 17,15 17,5 9,10" fill="black"></polygon>
                        </svg>
                    </button>
                    <button class="cls" title="清空消息记录" type="button">
                        <svg width="19" height="19">
                            <polygon points="12,1 0,13 2,15 9,15 14.5,9.5 14,8 8,14 3,14 2,13 10,5 14.5,9.5 17.5,6.5"
                                fill="black" />
                            <polygon points="18,17 18,16 0,16 0,17" fill="black" />
                        </svg>
                    </button>
                    <button class="move" title="移动窗口位置" type="button">
                        <svg width="19" height="19">
                            <polygon points="1,1 1,5 5,1" fill="black" />
                            <polygon points="17,1 13,1 17,5" fill="black" />
                            <polygon points="1,17 1,13 5,17" fill="black" />
                            <polygon points="17,17 17,13 13,17" fill="black" />
                        </svg>
                    </button>
                    <button class="min" title="缩小面板" type="button">
                        <svg width="19" height="19">
                            <rect x="2" y="8" width="14" height="2" fill="black" />
                            <rect class="vline" x="8" y="2" width="2" height="14" fill="black" />
                        </svg>
                    </button>
                </div>
                <div class="msgs"></div>
                <div class="footer">
                    <input class="port" name="port" value="6789" type="number" min="0" max="65535" title="端口号">
                    <button class="start" type="button">启动</button>
                </div>
            </div>
        </div>
        <dialog id="beibeibeibei-panel-rule-dialog">
            <div class="title">
                <button class="close" aria-label="关闭规则面板" type="button">
                    <svg width="10" height="10">
                        <line x1="0" y1="0" x2="10" y2="10" stroke="white" />
                        <line x1="0" y1="10" x2="10" y2="0" stroke="white" />
                    </svg>
                </button>
            </div>
            <div class="table">
                <div class="column header">
                    <div>规则名</div>
                    <div>网址包含文字</div>
                    <div>选择器A</div>
                    <div>选择器A数量限制</div>
                    <div>选择器B</div>
                    <div title="从0开始">选择器B的第几项</div>
                    <div>对选择器B的操作</div>
                    <div>操作数据</div>
                    <div>规则删除</div>
                </div>
                <button class="add" type="button">
                    <div>添加新规则</div>
                </button>
            </div>
        </dialog>
        <dialog id="beibeibeibei-panel-add-rule-dialog">
            <div class="focus-start" tabindex="0"></div>
            <div class="title">
                <button class="close" aria-label="关闭添加规则对话框" type="button">
                    <svg width="10" height="10">
                        <line x1="0" y1="0" x2="10" y2="10" stroke="white" />
                        <line x1="0" y1="10" x2="10" y2="0" stroke="white" />
                    </svg>
                </button>
            </div>
            <div class="add-panel">
                <div class="add-panel-item">1.收到 <input class="rule-name" title="规则名称" name="rule-name"
                        spellcheck="false"> 消息
                </div>
                <div class="add-panel-item">2.网站地址包含 <input class="url-pattern" title="网址匹配文本" name="url-pattern"
                        spellcheck="false">
                </div>
                <div class="add-panel-item">
                    3.选择器 <input class="count-based-selector" title="选择器(数量限制)" name="count-based-selector"
                        spellcheck="false"> 的数量
                    <div class="quantitySelector custom-select position-right" title="数量限制条件" name="quantity-condition"
                        aria-label="数量限制条件">
                        <button class="select-button" type="button">请选择</button>
                        <div class="options-container" tabindex="-1">
                            <div class="option-item" data-value="1" tabindex="-1">无限制</div>
                            <div class="option-item" data-value="2" tabindex="-1">最少</div>
                            <div class="option-item" data-value="3" tabindex="-1">最多</div>
                            <div class="option-item" data-value="4" tabindex="-1">等于</div>
                            <div class="option-item" data-value="5" tabindex="-1">范围</div>
                        </div>
                    </div>
                    <span>
                        <span class="single-input">
                            <input type="number" class="quantity-value" title="数量值" name="quantity-value"
                                spellcheck="false"> 个
                        </span>
                        <span class="range-input">
                            在 <input type="number" class="min-quantity" title="最小数量" name="min-quantity"
                                spellcheck="false"> ~
                            <input type="number" class="max-quantity" title="最大数量" name="max-quantity"
                                spellcheck="false"> 之间
                        </span>
                    </span>
                </div>
                <div class="add-panel-item text-center">满足上述条件时将执行第4条</div>
                <div class="add-panel-item">
                    4.选择器 <input class="action-selector" title="目标选择器" name="action-selector" spellcheck="false"> 的第
                    <input type="number" class="action-index" title="目标选择器索引(从0开始)" name="action-index"
                        spellcheck="false"> 项会被
                    <div class="action-type custom-select position-right" title="对最终目标的操作" name="action-type"
                        aria-label="对最终目标的操作">
                        <button class="select-button" type="button">请选择</button>
                        <div class="options-container" tabindex="-1">
                            <div class="option-item" data-value="1" tabindex="-1">点击</div>
                            <div class="option-item" data-value="2" tabindex="-1">旋转</div>
                            <div class="option-item" data-value="3" tabindex="-1">缩放</div>
                        </div>
                    </div>
                    <input type="number" class="action-num" title="操作数据" name="action-num" spellcheck="false">
                </div>
            </div>
            <div class="footer">
                <button class="add" type="button">添加</button>
                <button class="test" type="button">模拟输入</button>
                <button class="cancel" type="button">返回</button>
            </div>
            <div class="focus-end" tabindex="0"></div>
        </dialog>
    </div>

    <script>
        function beibeibeibei_init() {
            /* 关闭dialog1 */
            document.querySelector("#beibeibeibei-panel-rule-dialog .title .close").addEventListener("click", (e) => {
                e.target.closest('dialog').parentElement.querySelectorAll('dialog').forEach((d) => {
                    d.close();
                })
            });
            /* 打开添加规则弹窗 */
            document.querySelector("#beibeibeibei-panel-rule-dialog .table .add").addEventListener("click", (e) => {
                document.querySelector('#beibeibeibei-panel-add-rule-dialog').showModal();
            });
            /* 关闭dialog2 title */
            document.querySelector("#beibeibeibei-panel-add-rule-dialog .title .close").addEventListener("click", (e) => {
                e.target.closest('dialog').close();
            });
            /* 关闭dialog2 返回*/
            document.querySelector("#beibeibeibei-panel-add-rule-dialog .footer .cancel").addEventListener("click", (e) => {
                e.target.closest('dialog').close();
            });

            /* 打开规则弹窗 */
            document.querySelector("#beibeibeibei-panel .rule").addEventListener("click", () => {
                /** @type {HTMLDialogElement} */
                let dialog = document.querySelector("#beibeibeibei-panel-rule-dialog");
                dialog.showModal();
            });

            /* 清空消息记录 */
            document.querySelector("#beibeibeibei-panel .cls").addEventListener("click", () => {
                let msgs = document.querySelector("#beibeibeibei-panel .msgs");
                msgs.replaceChildren();
            });

            // #region /* 缩小面板 */
            let panelIsMin = false;
            document.querySelector("#beibeibeibei-panel .min").addEventListener("click", () => {
                panelIsMin = !panelIsMin;

                let vl = document.querySelector("#beibeibeibei-panel .min .vline");
                vl.style.opacity = panelIsMin ? '1' : '0';
                vl.parentElement.parentElement.title = panelIsMin ? "恢复面板" : "缩小面板";

                let panel = document.querySelector("#beibeibeibei-panel");
                panel.style.width = panelIsMin ? "22px" : "300px";
                panel.style.height = panelIsMin ? "22px" : "180px";
            });
            // #endregion

            // #region /* 移动位置 */
            let panelpos = 3;
            document.querySelector("#beibeibeibei-panel .move").addEventListener("click", () => {
                panelpos = (panelpos + 1) % 4;
                updatePos();
            });
            function updatePos() {
                const wrapper = document.querySelector("#beibeibeibei-panel").parentElement.parentElement;
                const positions = [getComputedStyle(document.querySelector(".beibeibeibei-panel-warpper .topright")), getComputedStyle(document.querySelector(".beibeibeibei-panel-warpper .bottomright")), getComputedStyle(document.querySelector(".beibeibeibei-panel-warpper .bottomleft")), getComputedStyle(document.querySelector(".beibeibeibei-panel-warpper .topleft"))];

                wrapper.style.inset = positions[panelpos].inset;
                switch (panelpos) {
                    case 0:
                        wrapper.style.alignItems = "flex-start";
                        wrapper.style.justifyContent = "flex-end";
                        break;
                    case 1:
                        wrapper.style.alignItems = "flex-end";
                        wrapper.style.justifyContent = "flex-end";
                        break;
                    case 2:
                        wrapper.style.alignItems = "flex-end";
                        wrapper.style.justifyContent = "flex-start";
                        break;
                    case 3:
                        wrapper.style.alignItems = "flex-start";
                        wrapper.style.justifyContent = "flex-start";
                        break;
                }
            };
            const debounce = (fn, delay) => {
                let timer;
                return function () {
                    if (timer) {
                        clearTimeout(timer);
                    }
                    timer = setTimeout(() => {
                        fn();
                    }, delay);
                }
            };
            const cancalDebounce = debounce(updatePos, 200);

            window.addEventListener('resize', cancalDebounce);
            // #endregion
            /* 按下 ESC 键时关闭弹窗 */
            document.addEventListener('keydown', (event) => {
                if (event.key === 'Escape') {
                    let dialog = document.querySelector("#beibeibeibei-panel-rule-dialog");
                    dialog.close();
                    let dialog2 = document.querySelector("#beibeibeibei-panel-add-rule-dialog");
                    dialog2.close();
                }
            });

            // #region /* add-rule-dialog弹窗循环tab键功能 */
            const focusStart = document.querySelector("#beibeibeibei-panel-add-rule-dialog > div.focus-start")
            focusStart.addEventListener("focus", (event) => {
                let els = document.querySelector('#beibeibeibei-panel-add-rule-dialog').querySelectorAll("input, select, button");
                els[els.length - 1].focus();
            });
            const focusEnd = document.querySelector("#beibeibeibei-panel-add-rule-dialog > div.focus-end");
            focusEnd.addEventListener("focus", (event) => {
                let els = document.querySelector('#beibeibeibei-panel-add-rule-dialog').querySelectorAll("input, select, button");
                els[0].focus();
            });
            // #endregion

            // #region /* 根据选中的选项显示或隐藏对应的<span>元素 */
            const quantitySelector = document.querySelector('#beibeibeibei-panel-add-rule-dialog .quantitySelector');
            const inputSingle = document.querySelector('#beibeibeibei-panel-add-rule-dialog .add-panel-item .single-input');
            const inputRange = document.querySelector('#beibeibeibei-panel-add-rule-dialog .add-panel-item .range-input');
            inputSingle.style.display = 'none';
            inputRange.style.display = 'none';
            quantitySelector.addEventListener('change', function () {
                const selectedValue = this.querySelector('.select-button').getAttribute('data-value');
                // 根据选择值显示对应输入
                switch (selectedValue) {
                    case '1': // 无限制
                    default: // 其他情况隐藏所有输入
                        inputSingle.style.display = 'none';
                        inputRange.style.display = 'none';
                        break;
                    case '2': // 最少
                    case '3': // 最多
                    case '4': // 等于
                        inputSingle.style.display = 'inline';
                        inputRange.style.display = 'none';
                        break;
                    case '5': // 范围
                        inputSingle.style.display = 'none';
                        inputRange.style.display = 'inline';
                        break;
                }
            });
            // #endregion

            // #region /* 监听 dialog 关闭事件, 重置其中的内容 */
            const dialog2 = document.querySelector('#beibeibeibei-panel-add-rule-dialog');
            dialog2.addEventListener('close', () => {
                // 重置
                dialog2.querySelectorAll('input').forEach(input => {
                    input.value = '';
                });
                // 重置.custom-select组件
                dialog2.querySelectorAll('.custom-select').forEach(customSelect => {
                    const selectButton = customSelect.querySelector('.select-button');
                    const optionsContainer = customSelect.querySelector('.options-container');
                    selectButton.textContent = '请选择';
                    selectButton.removeAttribute('data-value');
                    optionsContainer.style.animation = 'none';// 移除现有动画
                    void optionsContainer.offsetWidth;// 强制触发重绘以重置动画
                });
                // 隐藏动态输入区域
                dialog2.querySelectorAll('.single-input, .range-input').forEach(el => {
                    el.style.display = 'none';
                });
            });
            // #endregion

            // #region /* 自定义select处理 */
            document.querySelectorAll('.custom-select').forEach(customSelect => {
                const selectButton = customSelect.querySelector('.select-button');
                const optionsContainer = customSelect.querySelector('.options-container');
                let isOpen = false;

                selectButton.addEventListener('click', function (e) {
                    // 切换选项可见性
                    e.stopPropagation();
                    if (isOpen) {
                        resetAndPlay(optionsContainer, 'reverse');
                        customSelect.querySelectorAll('.option-item').forEach(option => {
                            option.setAttribute('tabindex', '-1');
                        })
                    } else {
                        resetAndPlay(optionsContainer, 'normal');
                        customSelect.querySelectorAll('.option-item').forEach(option => {
                            option.setAttribute('tabindex', '0');
                        })
                    }
                    isOpen = !isOpen;
                });

                customSelect.querySelectorAll('.option-item').forEach(option => {
                    // 点击事件处理
                    option.addEventListener('click', function () {
                        selectButton.textContent = this.textContent;
                        selectButton.setAttribute('data-value', this.dataset.value);
                        if (isOpen) {
                            resetAndPlay(optionsContainer, 'reverse');
                            isOpen = false;
                        }
                        // 触发自定义的 change 事件
                        const changeEvent = new Event('change', { bubbles: true });
                        customSelect.dispatchEvent(changeEvent);
                    });
                    // 键盘事件处理
                    option.addEventListener('keydown', function (e) {
                        switch (e.key) {
                            case 'Enter':
                            case ' ':
                                e.preventDefault();
                                this.click();
                                selectButton.focus();
                                break;
                            case 'ArrowDown':
                                e.preventDefault();
                                const next = this.nextElementSibling || optionsContainer.firstElementChild;
                                next.focus();
                                break;
                            case 'ArrowUp':
                                e.preventDefault();
                                const prev = this.previousElementSibling || optionsContainer.lastElementChild;
                                prev.focus();
                                break;
                            case 'ArrowLeft':
                            case 'ArrowRight':
                                // 按左键或右键时, 将焦点返回到select-button
                                e.preventDefault();
                                selectButton.focus();
                                break;
                        }
                    });
                });
                document.addEventListener('click', function () {
                    // 点击页面其他区域关闭选项
                    if (isOpen) {
                        resetAndPlay(optionsContainer, 'reverse');
                        isOpen = false;
                    }
                });
                optionsContainer.addEventListener('click', function (e) {
                    // 防止选项容器点击时冒泡
                    e.stopPropagation();
                });
                selectButton.addEventListener('keydown', function (e) {
                    switch (e.key) {
                        case 'ArrowLeft':
                        case 'ArrowRight':
                            // 按左键或右键时, 将焦点切换到option里
                            if (isOpen) {
                                e.preventDefault();
                                customSelect.querySelector('.option-item')?.focus();
                            }
                            break;
                    }
                });
            });
            function resetAndPlay(el, direction) {
                // 移除现有动画
                el.style.animation = 'none';
                // 强制触发重绘以重置动画
                void el.offsetWidth;
                // 应用新动画设置
                el.style.animation = `custom-select-expand 0.1s ease-out ${direction} forwards`;
            }
            // #endregion

            // #region /* 模拟输入按钮 */
            let testBtn = document.querySelector("#beibeibeibei-panel-add-rule-dialog button.test");
            testBtn.addEventListener('click', () => {
                const dialog2 = testBtn.closest("dialog");

                // 填充文本输入框
                dialog2.querySelector('.rule-name').value = '旋转视频示例';
                dialog2.querySelector('.url-pattern').value = 'bilibili.com';
                dialog2.querySelector('.count-based-selector').value = 'video';
                dialog2.querySelector('.action-selector').value = 'video';
                dialog2.querySelector('.action-index').value = '0';

                // 设置数量条件选择器为"最多"
                const quantitySelector = dialog2.querySelector('.quantitySelector');
                const quantityButton = quantitySelector.querySelector('.select-button');
                quantityButton.textContent = '最多';
                quantityButton.dataset.value = '3';
                quantitySelector.dispatchEvent(new Event('change'));

                // 填充数量值
                dialog2.querySelector('.quantity-value').value = '1';

                // 设置操作类型为"点击"
                const actionTypeSelector = dialog2.querySelector('.action-type');
                const actionButton = actionTypeSelector.querySelector('.select-button');
                actionButton.textContent = '旋转';
                actionButton.dataset.value = '2';
                actionTypeSelector.dispatchEvent(new Event('change'));

                // 填充操作数值
                dialog2.querySelector('.action-num').value = '90'; // 新增字段
            })
            // #endregion

            // #region /* 添加新条目 */
            function collectRuleData() {
                let dialog2 = document.querySelector("#beibeibeibei-panel-add-rule-dialog");
                return {
                    ruleName: dialog2.querySelector('.rule-name').value.trim(),
                    urlPattern: dialog2.querySelector('.url-pattern').value.trim(),
                    selectorA: dialog2.querySelector('.count-based-selector').value.trim(),
                    quantityCondition: dialog2.querySelector('.quantitySelector .select-button').textContent,
                    quantityValue: getQuantityValues(dialog2),
                    selectorB: dialog2.querySelector('.action-selector').value.trim(),
                    actionIndex: dialog2.querySelector('.action-index').value.trim(),
                    actionType: dialog2.querySelector('.action-type .select-button').textContent,
                    actionNum: dialog2.querySelector('.action-num').value.trim()
                };
            }
            function getQuantityValues(dialog) {
                const condition = dialog.querySelector('.quantitySelector .select-button').dataset.value;
                switch (condition) {
                    case '2': // 最少
                    case '3': // 最多
                    case '4': // 等于
                        return dialog.querySelector('.quantity-value').value;
                    case '5': // 范围
                        return `${dialog.querySelector('.min-quantity').value}-${dialog.querySelector('.max-quantity').value}`;
                    default:
                        return '';
                }
            }
            function validateRuleData(data) {
                if (!data.ruleName) {
                    alert("规则名称不能为空");
                    return false;
                }
                if (data.quantityCondition !== "无限制" && !data.selectorA) {
                    alert("选择器A不能为空");
                    return false;
                }
                if (!data.selectorB) {
                    alert("选择器B不能为空");
                    return false;
                }
                if (isNaN(data.actionIndex) || data.actionIndex < 0) {
                    alert("索引值必须是非负数字");
                    return false;
                }
                return true;
            }
            function addRuleToStorage(ruleData) {
                const rules = GM_getValue('rulesData', []);
                const newRule = [
                    ruleData.ruleName,
                    ruleData.urlPattern,
                    ruleData.selectorA,
                    formatQuantityCondition(ruleData.quantityCondition, ruleData.quantityValue),
                    ruleData.selectorB,
                    ruleData.actionIndex,
                    ruleData.actionType,
                    ruleData.actionNum
                ];
                rules.push(newRule);
                GM_setValue('rulesData', rules);
            }
            function formatQuantityCondition(condition, value) {
                switch (condition) {
                    case '无限制': return '无限制';
                    case '最少': return `最少 ${value} 个`;
                    case '最多': return `最多 ${value} 个`;
                    case '等于': return `等于 ${value} 个`;
                    case '范围': return `范围 ${value} 个`;
                    default: return '无限制';
                }
            }
            function addRuleToUI(ruleData) {
                const ruleDialog = document.querySelector('#beibeibeibei-panel-rule-dialog');
                const newBody = document.createElement('div');
                newBody.className = 'column body';

                const fields = [
                    ruleData.ruleName,
                    ruleData.urlPattern,
                    ruleData.selectorA,
                    formatQuantityCondition(ruleData.quantityCondition, ruleData.quantityValue),
                    ruleData.selectorB,
                    ruleData.actionIndex,
                    ruleData.actionType,
                    ruleData.actionNum
                ];

                fields.forEach(text => {
                    const div = document.createElement('div');
                    div.textContent = text;
                    newBody.appendChild(div);
                });

                // 添加删除按钮
                const deleteDiv = document.createElement('div');
                const delBtn = document.createElement('button');
                delBtn.className = 'remove';
                delBtn.textContent = '删除此条';
                delBtn.onclick = function () {
                    const bodyElement = this.closest('.column.body');
                    const index = bodyElement.dataset.index;
                    // 从页面中删除元素
                    bodyElement.remove();
                    // 从存储的数据中删除对应条目
                    const savedData = GM_getValue('rulesData', []);
                    savedData.splice(index, 1);
                    GM_setValue('rulesData', savedData);
                };
                deleteDiv.appendChild(delBtn);
                newBody.appendChild(deleteDiv);

                // 插入到添加按钮之前
                const addBtn = ruleDialog.querySelector('.add');
                ruleDialog.querySelector('.table').insertBefore(newBody, addBtn);
            }
            let addBtn = document.querySelector("#beibeibeibei-panel-add-rule-dialog button.add");
            addBtn.addEventListener('click', () => {
                const ruleData = collectRuleData();
                if (validateRuleData(ruleData)) {
                    addRuleToStorage(ruleData);
                    addRuleToUI(ruleData);
                    addBtn.closest("dialog").close();
                }
            });
            // #endregion
        };

        function beibeibeibei_socket() {
            const startButton = document.querySelector("#beibeibeibei-panel .start");
            const testButton = document.querySelector("#beibeibeibei-panel .test");
            const portInput = document.querySelector("#beibeibeibei-panel input.port");
            const pborder = document.querySelector(".beibeibeibei-panel-border");
            const msgContainer = document.querySelector("#beibeibeibei-panel .msgs");
            /** @type {HTMLElement} */
            const led = document.querySelector("#beibeibeibei-panel .led");

            // 获取端口号
            const port = portInput.value.trim();
            // 定义 WebSocket 的 URL
            const wsUrl = `ws://localhost:${port}`;
            // 定义 WebSocket 实例和定时器
            /** @type {WebSocket} */
            let ws;
            let websocketCheckInterval;
            let websocketCheckIntervalTime = 1000;
            let messageCleanupInterval;
            let messageCleanupIntervalTime = 2000;
            // isrunning只是建议启动, 和 WebSocket 状态无关
            let isrunning = false;

            // 启动连接
            startButton.addEventListener("click", () => {
                isrunning = !isrunning;
                // 修改UI
                if (isrunning) {
                    startButton.textContent = '停止';
                    pborder.classList.add("running");
                } else {
                    startButton.textContent = '启动';
                    pborder.classList.remove("running");
                }
                // 控制 Websocket
                if (isrunning) {
                    // 如果 WebSocket 已经存在, 先关闭它
                    if (ws) {
                        ws.close();
                    }

                    // 创建新的 WebSocket 实例
                    ws = new WebSocket(wsUrl);

                    // 设置定时器, 间隔 intervalTimeout 毫秒检查一次 WebSocket 状态
                    websocketCheckInterval = setInterval(() => {
                        if (ws.readyState === WebSocket.CLOSING || ws.readyState === WebSocket.CLOSED) {
                            console.log("WebSocket 状态为 CLOSING 或 CLOSED, 尝试重新连接...");
                            appendMessage("info", `尝试重新连接`);
                            // 关闭当前 WebSocket 实例
                            ws.close();
                            // 创建新的 WebSocket 实例
                            ws = new WebSocket(wsUrl);
                            // 添加 WebSocket 的事件监听
                            ws.onopen = handleWebSocketOpen;
                            ws.onmessage = handleWebSocketMessage;
                            ws.onerror = handleWebSocketError;
                            ws.onclose = handleWebSocketClose;
                        }
                    }, websocketCheckIntervalTime);

                    // 设置定时器, 控制消息容器中的子元素数量
                    messageCleanupInterval = setInterval(() => {
                        const childrenCount = msgContainer.childElementCount;
                        if (childrenCount > 50) {
                            // 计算要删除的前 5% 子元素的数量
                            const deleteCount = Math.ceil(childrenCount * 0.05);
                            // 使用 requestIdleCallback 异步删除前 5% 的子元素
                            requestIdleCallback(() => {
                                for (let i = 0; i < deleteCount; i++) {
                                    if (msgContainer.childElementCount > 0) {
                                        msgContainer.removeChild(msgContainer.firstChild);
                                    }
                                }
                            });
                        }
                    }, messageCleanupIntervalTime);

                    // 添加 WebSocket 的事件监听
                    ws.onopen = handleWebSocketOpen;
                    ws.onmessage = handleWebSocketMessage;
                    ws.onerror = handleWebSocketError;
                    ws.onclose = handleWebSocketClose;
                } else {
                    // 停止定时器
                    if (websocketCheckInterval) {
                        clearInterval(websocketCheckInterval);
                        websocketCheckInterval = null;
                    }

                    // 停止定时器
                    if (messageCleanupInterval) {
                        clearInterval(messageCleanupInterval);
                        messageCleanupInterval = null;
                    }

                    // 关闭 WebSocket 连接
                    if (ws) {
                        ws.close();
                        ws = null;
                    }

                    console.log("WebSocket 连接已停止");
                }
            });

            // WebSocket 连接成功
            function handleWebSocketOpen() {
                console.log("WebSocket 连接成功");
                appendMessage("info", `已连接 WebSocket 服务器：${wsUrl}`);
                led.classList.add("websocket-connected");
                led.title = "连接状态: 已连接";
            }

            // WebSocket 收到消息
            function handleWebSocketMessage(/** @type { MessageEvent } */event) {
                console.log("收到消息：", event.data);
                appendMessage("msg", event.data);

                // 处理消息并执行规则
                beibeibeibei_processRules(event.data);
            }

            // WebSocket 发生错误
            function handleWebSocketError(event) {
                console.log("WebSocket 发生错误：", event);
                appendMessage("error", "WebSocket 连接错误");
            }

            // WebSocket 连接关闭
            function handleWebSocketClose(event) {
                console.log("WebSocket 已关闭");
                appendMessage("info", `WebSocket 连接已断开`);
                led.classList.remove("websocket-connected");
                led.title = "连接状态: 未连接";
            }

            // 测试按钮点击事件
            testButton.addEventListener("click", () => {
                if (ws && ws.readyState === WebSocket.OPEN) {
                    // 发送测试消息
                    const testMessage = "测试消息";
                    ws.send(testMessage);
                    appendMessage("info", `已发送测试消息：${testMessage}`);
                } else {
                    appendMessage("error", "WebSocket 连接未开启, 无法发送测试消息");
                }
            });

            // 显示消息
            function appendMessage(className, textContent) {
                const msg = document.createElement("p");
                msg.className = className;
                msg.textContent = textContent;
                msgContainer.appendChild(msg);

                // 获取滚动条位置和容器高度信息
                const isNearBottom = msgContainer.scrollTop + msgContainer.clientHeight >= msgContainer.scrollHeight * 0.9;
                // 如果滚动条接近底部，则滚动到底部
                if (isNearBottom) {
                    msgContainer.scrollTop = msgContainer.scrollHeight;
                }
            }
        }

        function runWhenDocumentReady(...funcs) {
            const validFuncs = [...new Set(funcs)].filter(item => typeof item === 'function');

            if (document.readyState === 'loading') {
                validFuncs.forEach(func =>
                    document.addEventListener('DOMContentLoaded', func)
                );
            } else {
                validFuncs.forEach(func => func());
            }
        }

        const gmStorage = {
            rulesData: [
                ['msg1', '', 'button', '无限制', '.testA', '0', '旋转', '90'],
                ['msg1', '', 'button', '无限制', '.testA', '0', '缩放', '1.1'],
                ['msg1', '', 'button', '无限制', '.testA', '0', '点击', ''],
                ['msg-test', '', '.test-element', '最少 6 个', '.test-element', '0', '旋转', '135']
            ]
        };

        function GM_setValue(key, value) {
            gmStorage[key] = value;
            console.log("当前gmStorage内容:", JSON.parse(JSON.stringify(gmStorage)));
        }
        function GM_getValue(key, defaultValue) {
            return gmStorage.hasOwnProperty(key) ? gmStorage[key] : defaultValue;
        }

        // 保存规则数据
        function beibeibeibei_saveRulesData() {
            const bodyElements = document.querySelectorAll('#beibeibeibei-panel-rule-dialog .column.body');
            const savedData = [];

            bodyElements.forEach((element, index) => {
                const children = element.children;
                const rowData = [];
                for (let i = 0; i < children.length; i++) {
                    if (i === children.length - 1) {
                        // 跳过最后一个包含按钮的div
                        continue;
                    }
                    rowData.push(children[i].textContent.trim());
                }
                savedData.push(rowData);
            });

            GM_setValue('rulesData', savedData);
            console.log('规则数据已保存');
        }

        // 恢复规则数据
        function beibeibeibei_restoreRulesData() {
            const savedData = GM_getValue('rulesData', []);
            const headerElement = document.querySelector('#beibeibeibei-panel-rule-dialog .column.header');
            const addageElement = document.querySelector('#beibeibeibei-panel-rule-dialog .add');
            const bodyElements = document.querySelectorAll('#beibeibeibei-panel-rule-dialog .column.body');

            // 清除现有的body元素
            bodyElements.forEach(element => {
                element.remove();
            });

            // 恢复保存的内容
            savedData.forEach((rowData, index) => {
                const newBody = document.createElement('div');
                newBody.className = 'column body';
                newBody.dataset.index = index;

                if (rowData.length < 8) {
                    rowData = rowData.concat([null]);
                }

                rowData.forEach((data) => {
                    const div = document.createElement('div');
                    div.textContent = data || '';
                    newBody.appendChild(div);
                });

                // 添加删除按钮
                const deleteDiv = document.createElement('div');
                const delBtn = document.createElement('button');
                delBtn.className = 'remove';
                delBtn.textContent = '删除此条';
                delBtn.type = 'button';
                delBtn.onclick = function () {
                    const bodyElement = this.closest('.column.body');
                    const index = bodyElement.dataset.index;
                    // 从页面中删除元素
                    bodyElement.remove();
                    // 从存储的数据中删除对应条目
                    const savedData = GM_getValue('rulesData', []);
                    savedData.splice(index, 1);
                    GM_setValue('rulesData', savedData);
                };
                deleteDiv.appendChild(delBtn);
                newBody.appendChild(deleteDiv);

                // 插入到header和add按钮之间
                headerElement.parentNode.insertBefore(newBody, addageElement);
            });
        }

        // 执行规则
        function beibeibeibei_processRules(message) {
            // 获取所有保存的规则
            const rules = GM_getValue('rulesData', []);
            // 过滤规则
            const filteredRules = rules.filter(item => {
                // 确保 item 是数组且数组不为空
                if (!Array.isArray(item) || item.length < 8) return false;
                // 检查第 0 项是否匹配 message
                const messageMatch = item[0] === message;
                // 检查 URL 是否包含第 1 项
                const urlMatch = urlContainsText(item[1]);
                // 检查元素数量是否满足条件
                const selector2 = item[2]; // 第2项是选择器
                const condition = item[3]; // 第3项是条件
                const elementCountMatch = checkElementCount(selector2, condition);
                // 检查第4项选择器的数量是否大于等于第5项
                const selector4 = item[4]; // 第4项是选择器
                const selector4Count = parseInt(item[5]); // 第5项是第几项(从0开始)
                const selector4CountMatch = checkElementCount(selector4, `最少 ${selector4Count + 1} 个`);
                // 返回所有条件都满足的规则
                return messageMatch && urlMatch && elementCountMatch && selector4CountMatch;
            });

            console.log({ 0: 'beibeibeibei_processRules的filteredRules结果', message, filteredRules });

            // 执行符合条件的规则
            filteredRules.forEach((rule) => {
                const elements = document.querySelectorAll(rule[4]);
                if (elements.length > parseInt(rule[5])) {
                    const targetIndex = parseInt(rule[5]);
                    const targetElement = elements[targetIndex];

                    // 执行操作
                    switch (rule[6]) {
                        case '点击':
                            /* svg是没有click方法的 */
                            if (typeof targetElement.click === 'function') {
                                targetElement.click();
                            } else {
                                targetElement.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
                            }
                            break;
                        case '旋转':
                            const rotateValue = parseInt(rule[7]) || 0;
                            let targetElementRotate = parseInt(getComputedStyle(targetElement).rotate) || 0;
                            targetElement.style.rotate = `${(targetElementRotate + rotateValue) % 360}deg`;
                            break;
                        case '缩放':
                            const scaleValue = rule[7];
                            targetElement.style.transform = `scale(${scaleValue})`;
                            break;
                    }
                }
            });
        }
        // 正则匹配当前网址
        function urlMatchesPattern(pattern) {
            const currentUrl = window.location.href;
            const regex = new RegExp(pattern);
            return regex.test(currentUrl);
        }
        // 普通文本匹配当前网址
        function urlContainsText(text) {
            const currentUrl = window.location.href;
            return currentUrl.includes(text);
        }
        // 检查元素数量
        function checkElementCount(selector, condition) {
            if (condition === '无限制') {
                // 无限制的意思就是无限制, 有没有元素都行, 选择器无效都行
                return true;
            }
            // 验证选择器是否有效
            if (!selector || typeof selector !== 'string' || selector.trim() === '') {
                // console.error('无效的选择器:', selector);
                return false; // 或抛出更明确的错误
            }

            // 获取匹配指定 CSS 选择器的元素个数
            const elements = document.querySelectorAll(selector);
            const count = elements.length;

            // 解析条件
            let min = 0;
            let max = Infinity;
            let exact = null;
            let range = null;

            // 正则表达式用于提取数字
            const numberRegex = /\d+/g;

            // 根据条件类型解析
            if (condition === '无限制') {
                // 无限制的意思就是无限制, 有没有元素都行
                return true;
            } else if (condition.startsWith('最少')) {
                // 最少 N 个
                const numbers = condition.match(numberRegex);
                if (numbers && numbers.length > 0) {
                    min = parseInt(numbers[0]);
                    return count >= min;
                }
            } else if (condition.startsWith('最多')) {
                // 最多 N 个
                const numbers = condition.match(numberRegex);
                if (numbers && numbers.length > 0) {
                    max = parseInt(numbers[0]);
                    return count <= max;
                }
            } else if (condition.startsWith('等于')) {
                // 等于 N 个
                const numbers = condition.match(numberRegex);
                if (numbers && numbers.length > 0) {
                    exact = parseInt(numbers[0]);
                    return count === exact;
                }
            } else if (condition.startsWith('范围')) {
                // 范围 A-B 个
                const numbers = condition.match(numberRegex);
                if (numbers && numbers.length === 2) {
                    min = parseInt(numbers[0]);
                    max = parseInt(numbers[1]);

                    // 如果颠倒, 自动调换
                    if (min > max) {
                        [min, max] = [max, min];
                    }

                    return count >= min && count <= max;
                }
            } else {
                console.error('不支持的条件格式');
                return false;
            }

            return false;
        }

        runWhenDocumentReady(beibeibeibei_socket, beibeibeibei_restoreRulesData, beibeibeibei_init);

        // 用于临时测试
        setTimeout(() => {
            // 添加测试目标元素
            const testArea = document.createElement("div");
            testArea.className = "test-area"; // 添加样式类
            testArea.id = "test-area";
            testArea.style.position = 'fixed';
            testArea.style.top = '200px';
            testArea.style.left = '200px';
            testArea.style.width = "300px";
            testArea.style.height = "200px";
            testArea.style.background = "linear-gradient(135deg,#FFD26F 15%,#3677FF 100%)";
            testArea.style.padding = "20px";
            testArea.style.display = "flex";
            testArea.style.flexWrap = "wrap";
            testArea.style.justifyContent = "flex-start";
            testArea.style.alignItems = "flex-start";
            document.body.appendChild(testArea);

            // 添加一些可点击、可旋转、可缩放的元素
            for (let i = 0; i < 6; i++) {
                const testElement = document.createElement("div");
                testElement.className = "test-element";
                testElement.style.margin = "10px";
                testElement.style.width = "80px";
                testElement.style.height = "60px";
                testElement.style.display = "flex";
                testElement.style.justifyContent = "center";
                testElement.style.alignItems = "center";
                testElement.style.backgroundColor = "#e0e0e0";
                testElement.style.borderRadius = "5px";
                testElement.style.boxShadow = "0 1px 3px rgba(0, 0, 0, 0.2)";
                testElement.style.cursor = "pointer";
                testElement.style.fontSize = "14px";
                testElement.style.transition = "all 0.3s ease";

                testElement.innerHTML = `<span>测试元素 ${i + 1}</span>`;

                testElement.addEventListener("click", function () {
                    console.log(`测试元素 ${i + 1} 被点击了`);
                });

                testArea.appendChild(testElement);
            }

            document.querySelector("#beibeibeibei-panel > div.titlebar > button.rule").click();
            beibeibeibei_processRules('msg-test');
        }, 40);
    </script>
</body>

</html>